package cc.rengu.igas.channel.wechat.core.packswitch;

import cc.rengu.igas.channel.wechat.common.constant.WechatParamConstant;
import cc.rengu.igas.channel.wechat.common.constant.WechatTreeNodeConstant;
import cc.rengu.igas.channel.wechat.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.wechat.core.realize.WechatSignService;
import cc.rengu.igas.channel.wechat.core.realize.impl.WechatSignServiceImpl;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.KeyInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.KeyInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.cache.UnifiedCache;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

/**
 * 与微信实名验证通讯层报文解包前后、组前包后实现类
 * Created by 王成 on 2018/5/31.
 */
public class WechatAuthClientPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {
    RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public byte[] beforeInComPackSwitch(byte[] bytes) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        /* 获取数字签名字符串 */
        String jsonBefore = new String(bytes, "UTF-8");
        rglog.debug("接收报文体:[{}]", jsonBefore);
        JSONObject jsonObject = JSON.parseObject(jsonBefore);
        if (jsonObject == null) {
            String url = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE);
            if (url.contains("cancel")) {
                rglog.info("撤销申请单，应答报文体为空");
                jsonObject = new JSONObject();
                jsonObject.put("return_code", WechatParamConstant.STRING_SUCCESS);
            } else {
                rglog.error("接收微信报文异常!");
                JSONObject json = new JSONObject();
                json.put("return_code", RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode());
                json.put("return_msg", RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
                json.put("err_code", RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode());
                json.put("err_code_des", RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
                return json.toString().getBytes("UTF-8");
            }
        } else {
            if (jsonObject.containsKey("applyment_id")) {
                jsonObject.put("applyment_id", String.valueOf(jsonObject.get("applyment_id")));
            }
            String signData = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_SIGNATURE);
            String respTimeStamp = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_TIMESTAMP);
            String respNonceStr = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_NONCE);
            String serialNoRsp = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_CERT_SERIAL_NO);
            rglog.trace("获取应答证书序列号为:<{}>", serialNoRsp);
            rglog.trace("signData:<{}>", signData);
            rglog.trace("respTimeStamp:<{}>", respTimeStamp);
            rglog.trace("respNonceStr:<{}>", respNonceStr);

            /* 生成生成数字签名的字符串 */
            StringBuilder signBlock = new StringBuilder();
            signBlock.append(respTimeStamp).append("\n").append(respNonceStr).append("\n").append(jsonBefore).append("\n");
            rglog.debug("加签Block:<{}>", signBlock.toString());
            /* 获取微信验签密钥信息 */
            CertInfo certInfo = null;
            DstChannelCfg dstChannelCfg = (DstChannelCfg) xmlTreeUtil.getXmlTreeObjectValue(WechatTreeNodeConstant.DST_CHANNEL_CFG, DstChannelCfg.class);
            String secPlanInfoListString = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.SEC_PLAN_INFO_LIST);
            List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.V3_VERIFY_CERT_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                certInfo = certInfoMapper.selectCertInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
            }
            if (certInfo == null) {
                rglog.error("根据证书索引获取证书失败[{}]");
                throw new BizException(RespCodeEnum.GENERATE_SIGN_ERROR.getRespCode(), RespCodeEnum.GENERATE_SIGN_ERROR.getRespDesc());
            }
            if (serialNoRsp != null && !serialNoRsp.equals(certInfo.getCertDn())) {
                rglog.error("微信使用的平台证书序列号和当前所持有的微信支付平台证书的序列号不一致，请重新获取证书");
                //刷新证书

                getV3WechatPlatCert(instId, dstChannelCfg);
                jsonObject.put("return_code", RespCodeEnum.TRANS_SUCCESS.getRespCode());
                jsonObject.put("return_msg", RespCodeEnum.TRANS_SUCCESS.getRespDesc());
                jsonObject.put("err_code", RespCodeEnum.TRANS_SUCCESS.getRespCode());
                jsonObject.put("err_code_des", RespCodeEnum.TRANS_SUCCESS.getRespDesc());
                rglog.info("jsonObject  = <{}>", jsonObject.toJSONString());
                return jsonObject.toString().getBytes("UTF-8");
            }
            Certificate certificate = (Certificate) UnifiedCache.get("WECHATV3PLAT", certInfo.getCertDn());
            if (null == certificate) {
                rglog.error("证书未在本地缓存中，请刷新本地缓存后处理，但此功能未开发，建议重新上传图片以重新加载缓存");
                certificate = getV3WechatPlatCert(instId, dstChannelCfg);
            }
            WechatSignService wechatSignService = new WechatSignServiceImpl();
            // boolean verifyFlag = wechatSignService.verifySignString(signData,signBlock.toString(),certInfo);
            boolean verifyFlag = RSAUtil.verifySignString(signBlock.toString(), signData.toString(), (RSAPublicKey) certificate.getPublicKey(), certInfo.getAlgorithmType(), "UTF-8");
            if (!verifyFlag) {
                rglog.error("验签失败!");
                jsonObject.put("return_code", RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode());
                jsonObject.put("return_msg", RespCodeEnum.VERIFY_SIGN_ERROR.getRespDesc());
                jsonObject.put("err_code", RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode());
                jsonObject.put("err_code_des", RespCodeEnum.VERIFY_SIGN_ERROR.getRespDesc());
                return jsonObject.toString().getBytes("UTF-8");
            }
        }
        return jsonObject.toJSONString().getBytes("UTF-8");
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        if (!xmlTreeUtil.isExist("respCode")) {
            xmlTreeUtil.setXmlTreeStringValue("respCode", RespCodeEnum.TRANS_SUCCESS.getRespCode());
        }
        if (!xmlTreeUtil.isExist("respDesc")) {
            xmlTreeUtil.setXmlTreeStringValue("respDesc", RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        }
        if (!xmlTreeUtil.isExist("errCode")) {
            xmlTreeUtil.setXmlTreeStringValue("errCode", RespCodeEnum.TRANS_SUCCESS.getRespCode());
        }
        if (!xmlTreeUtil.isExist("errCodeDes")) {
            xmlTreeUtil.setXmlTreeStringValue("errCodeDes", RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        }
        return 0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        return 0;
    }

    @Override
    public byte[] afterOutgoPackSwitch(byte[] bytes) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        CertInfo certInfo = null;
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        DstChannelCfg dstChannelCfg = (DstChannelCfg) xmlTreeUtil.getXmlTreeObjectValue(WechatTreeNodeConstant.DST_CHANNEL_CFG, DstChannelCfg.class);

        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelCfg.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.V3_SIGN_CERT_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                certInfo = certInfoMapper.selectCertInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
            }
        }
        if (certInfo == null) {
            rglog.error("获取服务商签名密钥失败");
            throw new BizException(RespCodeEnum.GET_THIRD_MCHNT_KEY_ERROR.getRespCode(), RespCodeEnum.GET_THIRD_MCHNT_KEY_ERROR.getRespDesc());
        }
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.CERT_ID, certInfo.getCertDn());
        rglog.debug("设置报文头");
        //设置报文头
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Content-Type", "application/json");
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Accept", "application/json");
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0");
        String method = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.DEFINE_HTTP_METHOD_NODE);
        /**微信实名认证加签
         * 1、HTTP请求方法\n
         * 2、URL\n(获取请求的绝对URL，并去除域名部分得到参与签名的URL)
         * 3、请求时间戳\n
         * 4、请求随机串\n
         * 5、请求报文主体\n
         */
        String jsonBefore = new String(bytes, "UTF-8");
        if (!"GET".equals(method)) {
            try {
                JSONObject jsonObject = JSONObject.parseObject(jsonBefore);
                if (jsonObject.containsKey("identification_info")) {
                    JSONArray identification_valid_date = jsonObject.getJSONObject("identification_info").getJSONArray("identification_valid_date");
                    rglog.info("identification_valid_date:" + identification_valid_date.toString());
                    jsonObject.getJSONObject("identification_info").put("identification_valid_date", identification_valid_date.toString());
                    jsonBefore = jsonObject.toJSONString();
                }
                if (jsonObject.containsKey("subject_info")) {
                    if (jsonObject.getJSONObject("subject_info").containsKey("business_licence_info")) {
                        JSONArray licence_valid_date = jsonObject.getJSONObject("subject_info").getJSONObject("business_licence_info").getJSONArray("licence_valid_date");
                        rglog.info("licence_valid_date:" + licence_valid_date.toString());
                        jsonObject.getJSONObject("subject_info").getJSONObject("business_licence_info").put("licence_valid_date", licence_valid_date.toString());
                        jsonBefore = jsonObject.toJSONString();
                    }
                    if (jsonObject.getJSONObject("subject_info").containsKey("business_licence_info")) {
                        JSONArray licence_valid_date = jsonObject.getJSONObject("subject_info").getJSONObject("business_licence_info").getJSONArray("licence_valid_date");
                        rglog.info("licence_valid_date:" + licence_valid_date.toString());
                        jsonObject.getJSONObject("subject_info").getJSONObject("business_licence_info").put("licence_valid_date", licence_valid_date.toString());
                        jsonBefore = jsonObject.toJSONString();
                    }
                    if (jsonObject.getJSONObject("subject_info").containsKey("certificate_info")) {
                        JSONArray cert_vaild_date = jsonObject.getJSONObject("subject_info").getJSONObject("certificate_info").getJSONArray("cert_vaild_date");
                        rglog.info("cert_vaild_date:" + cert_vaild_date.toString());
                        jsonObject.getJSONObject("subject_info").getJSONObject("certificate_info").put("cert_vaild_date", cert_vaild_date.toString());
                        jsonBefore = jsonObject.toJSONString();
                    }
                }
            } catch (Exception e) {
                rglog.error("错误");
            }
        }
        String url = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE);
        if (url != null && !url.isEmpty()) {
            url = url.substring(url.indexOf("/v3"), url.length());
        }

        String nonceStr = RandomUtil.randomString(WechatTreeNodeConstant.WX_RAND_STR_LEN);
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_RAND_STR, nonceStr);
        long timestamp = System.currentTimeMillis() / 1000;
        String breakFlag = "\n";
        StringBuilder sb = new StringBuilder();
        if ("GET".equals(method)) {
            sb.append(method).append(breakFlag).append(url).append(breakFlag).append(timestamp).append(breakFlag).append(nonceStr).append(breakFlag).append(breakFlag);
        } else {
            sb.append(method).append(breakFlag).append(url).append(breakFlag).append(timestamp).append(breakFlag).append(nonceStr).append(breakFlag).append(jsonBefore).append(breakFlag);
        }
        /* 生成生成数字签名的字符串 */
        rglog.debug("系统加签Block:<{}>,长度 = <{}>", sb.toString(), sb.length());

        WechatSignService wechatSignService = new WechatSignServiceImpl();
        String signData = wechatSignService.generateSignString(sb.toString(), certInfo);
        if (null == signData) {
            rglog.error("生成数字签名失败!");
            throw new BizException(RespCodeEnum.GENERATE_SIGN_ERROR.getRespCode(), RespCodeEnum.GENERATE_SIGN_ERROR.getRespDesc());
        }
        rglog.debug("数字签名:<{}>", signData);
        /* 将数字签名设置到报文中 */
        String httpSignHead = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + dstChannelCfg.getProviderMchntNo() + "\",nonce_str=\"" + nonceStr + "\",signature=\"" + signData + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + certInfo.getCertDn() + "\"";

        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_AUTHORIZATION, httpSignHead);
        if (xmlTreeUtil.isExist("_MESSAGEHEAD/http/Wechatpay-Serial")) {
            xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/ArgList", "Accept:Content-Type:User-Agent:Authorization:Wechatpay-Serial");
        } else {
            xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/ArgList", "Accept:Content-Type:User-Agent:Authorization");
        }
        rglog.debug("报文头设置完成");
        if (null == bytes || 2 >= bytes.length) {
            return new byte[0];
        } else {
            return jsonBefore.getBytes("UTF-8");
        }
    }

    private Certificate getV3WechatPlatCert(String instId, DstChannelCfg dstChannelCfg) throws Exception {
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(instId, "wechatV3", "proxyHost");
        if (null == sysParam) {
            rglog.error("未配置微信V3接口代理服务器,wechatV3,proxyHost");
            throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
        }
        String proxyHost = sysParam.getParamValue();
        sysParam = sysParamService.getSysParamInfo(instId, "wechatV3", "proxyPort");
        if (null == sysParam) {
            rglog.error("未配置微信V3接口代理服务器,wechatV3,proxyPort");
            throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
        }
        int proxyPort = Integer.valueOf(sysParam.getParamValue()).intValue();
        //获取商户证书
        CertInfo certInfo = null;
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelCfg.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.V3_SIGN_CERT_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                certInfo = certInfoMapper.selectCertInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
            }
        }
        if (certInfo == null) {
            rglog.error("未配置商户密钥");
            throw new BizException(RespCodeEnum.PUB_CERT_NOT_EXIST.getRespCode(), RespCodeEnum.PUB_CERT_NOT_EXIST.getRespDesc());
        }
        // 换行符
        String LINE_END = "\r\n";
        String PREFIX = "--";
        // 定义数据分隔线
        String BOUNDARY = UUID.randomUUID().toString().replaceAll("-", "");
        //时间戳
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //随机数
        String nonce_str = RandomUtil.randomString(32);

        //拼签名串
        StringBuffer sb = new StringBuffer();
        sb.append("GET").append("\n");
        sb.append("/v3/certificates").append("\n");
        sb.append(timestamp).append("\n");
        sb.append(nonce_str).append("\n");
        sb.append("\n");
        rglog.info("签名原串:<{}>", sb.toString());

        WechatSignService wechatSignService = new WechatSignServiceImpl();
        String signData = wechatSignService.generateSignString(sb.toString(), certInfo);

        //拼装http头的Authorization内容
        String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + dstChannelCfg.getProviderMchntNo() + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + signData + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + certInfo.getCertDn() + "\"";
        rglog.debug("authorization值:" + authorization);
        String certDownloadUrl = "https://api.mch.weixin.qq.com/v3/certificates";
        //接口URL
        URL url = new URL(certDownloadUrl);
        InetSocketAddress addr = new InetSocketAddress(proxyHost, proxyPort);
        Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
        // 设置为POST
        conn.setRequestMethod("GET");
        // 发送POST请求必须设置如下两行
        conn.setUseCaches(false);
        // 设置请求头参数
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("Authorization", authorization);
        conn.setRequestProperty("User-Agent", "https://zh.wilipedia.org/wiki/User_agent");

        OutputStream outputStream = null;
        InputStream is = null;
        try {
            outputStream = conn.getOutputStream();
        } catch (IOException e) {
            rglog.error(e.getMessage());
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    rglog.error(e.getMessage());
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    rglog.error(e.getMessage());
                }
            }
        }
        //接收返回
        //打印返回头信息
        rglog.debug("接口返回头信息:");
        Map<String, List<String>> responseHeader = conn.getHeaderFields();
        for (Map.Entry<String, List<String>> entry : responseHeader.entrySet()) {
            rglog.debug(entry.getKey() + ":" + entry.getValue());
        }
        String data = "";
        //打印返回内容
        int responseCode = conn.getResponseCode();
        String rescontent = "";
        InputStream inputStream = null;
        try {
            if ((String.valueOf(responseCode)).startsWith("2")) {
                //成功
                inputStream = conn.getInputStream();
                rescontent = new String(InputStreamTOByte(inputStream));
                rglog.debug("证书下载成功:" + rescontent);
                JSONObject json = JSONObject.parseObject(rescontent);
                JSONArray dataArray = json.getJSONArray("data");
                //解密微信平台证书，并更新
                /* 根据通道安全计划获取安全计划 */
                KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                KeyInfo keyInfo = new KeyInfo();
                if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
                    Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.V3_AES_KEY_TYPE)).findFirst();
                    if (secPlanInfoOpt.isPresent()) {
                        keyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                    }
                }
                JSONObject allCertInfo = (JSONObject) dataArray.get(0);
                String serialNo = allCertInfo.getString("serial_no");
                rglog.info("serialNo = <{}>", serialNo);
                JSONObject encryptCert = allCertInfo.getJSONObject("encrypt_certificate");
                rglog.info("encryptCert = <{}>", encryptCert);
                String nonce = encryptCert.getString("nonce");
                rglog.info("nonce = <{}>", nonce);
                String associatedData = encryptCert.getString("associated_data");
                rglog.info("associatedData = <{}>", associatedData);
                String cipherText = encryptCert.getString("ciphertext");
                rglog.info("cipherText = <{}>", cipherText);
                rglog.debug("keyInfo = <{}>", JSON.toJSONString(keyInfo));
                String apiV3AesSecret = keyInfo.getKeyValue();
                String wechatPlatCertValue = AESUtil.gcmDecryptToString(apiV3AesSecret.getBytes(), associatedData.getBytes(), nonce.getBytes(), cipherText);
                //更新到微信平台证书中
                if (!StringUtil.isEmptyOrNull(wechatPlatCertValue)) {
                    //需处理wechatPlatCertValue值得证书头和尾
                    // wechatPlatCertValue = wechatPlatCertValue.substring(wechatPlatCertValue.indexOf("\n"),wechatPlatCertValue.lastIndexOf("\n")).replaceAll("\n","");
                    CertificateFactory cf = CertificateFactory.getInstance("X509");
                    ByteArrayInputStream inputStream1 = new ByteArrayInputStream(wechatPlatCertValue.getBytes(StandardCharsets.UTF_8));
                    Certificate certificate = null;
                    try {
                        certificate = cf.generateCertificate(inputStream1);
                    } catch (CertificateException ce) {
                        ce.printStackTrace();
                    }
                    UnifiedCache.set("WECHATV3PLAT", serialNo, certificate);
                    CertInfo pubCertInfo = null;
                    /* 根据通道安全计划获取安全计划 */
                    if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
                        Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.V3_VERIFY_CERT_TYPE)).findFirst();
                        if (secPlanInfoOpt.isPresent()) {
                            CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                            pubCertInfo = certInfoMapper.selectCertInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                        }
                    }
                    if (pubCertInfo == null) {
                        rglog.error("微信服务商[{}]未配置加密公钥");
                        throw new BizException(RespCodeEnum.PUB_CERT_NOT_EXIST.getRespCode(), RespCodeEnum.PUB_CERT_NOT_EXIST.getRespDesc());
                    }
                    CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                    pubCertInfo.setCertValue(wechatPlatCertValue);
                    pubCertInfo.setCertDn(serialNo);
                    certInfoMapper.updateCertInfoByPrimaryKey(pubCertInfo);
                    return certificate;
                }
            } else {
                //失败
                inputStream = conn.getErrorStream();
                rescontent = new String(InputStreamTOByte(inputStream));
                rglog.debug("证书下载失败:" + rescontent);
            }
        } catch (Exception e) {
            rglog.error(e.getMessage());
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {
                    rglog.error(e.getMessage());
                }
            }
        }
        return null;
    }

    public static byte[] InputStreamTOByte(InputStream in) throws IOException {

        int BUFFER_SIZE = 4096;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;

        while ((count = in.read(data, 0, BUFFER_SIZE)) != -1) {
            outStream.write(data, 0, count);
        }

        data = null;
        byte[] outByte = outStream.toByteArray();
        try {
            if (outStream != null) {
                outStream.close();
            }
        } catch (Exception e) {

        }
        return outByte;
    }
}
